import copy
import datetime
import math
import os
import sys
import time
from itertools import groupby
from operator import itemgetter
import numpy as np
from tqdm import tqdm

from src.utils import CommonUtils

# 将工程目录加入包扫描
currPath = os.path.abspath(os.path.dirname(__file__))
srcPath = os.path.split(currPath)[0]
rootPath = os.path.split(srcPath)[0]
projectPath = os.path.split(rootPath)[0]
sys.path.append(projectPath)

from src.db.ProdDb import ProdDb
from src.utils.CommonUtils import cleanScreen
from src.utils.LogUtils import Logger


class CalcIndicatorQuantile:
    """
    财务指标分位值计算
    """

    def __init__(self, logger, localDb):
        self.logger = logger
        self.localDb = localDb
        self.indexMapping = {}
        self.industryMapping = {
            "A": "农、林、牧、渔业",
            "B": "采矿业",
            "C": "制造业",
            "D": "电力、热力、燃气及水生产和供应业",
            "E": "建筑业",
            "F": "批发和零售业",
            "G": "交通运输、仓储和邮政业",
            "H": "住宿和餐饮业",
            "I": "信息传输、软件和信息技术服务业",
            "J": "金融业",
            "K": "房地产业",
            "L": "租赁和商务服务业",
            "M": "科学研究和技术服务业",
            "N": "水利、环境和公共设施管理业",
            "O": "居民服务、修理和其他服务业",
            "P": "教育",
            "Q": "卫生和社会工作",
            "R": "文化、体育和娱乐业",
            "S": "综合",
            "platform": "城投"
        }

    # 抽取企业指标数据
    def __loadFinIndexList__(self, year, indexCode):

        entTypes = ['T001', 'T002']

        sql = """
                SELECT
                    case when ent_type = 'T002'
                    then 'platform'
                    else e.srm_trade_type_superior
                    end as industry,
                    e.credit_code,
                    a.index_code,
                    a.index_value
                FROM
                    ent_enterprise e
                    INNER JOIN fin_index a ON e.credit_code = a.credit_code
                WHERE 
                    e.ent_type in %s
                    AND a.year = %s
                    AND a.index_code = %s
                    AND a.report_type = 3 
                    AND a.index_value IS NOT NULL
                ORDER BY industry, index_code                    
        """
        return self.localDb.Query(sql, (entTypes, year, indexCode))

    def __loadSettings__(self):
        sql = """
            SELECT
                `code`,
                `name`,
                T001,
                T002 
            FROM
                fin_index_calc_settings
            """
        return self.localDb.Query(sql)

    def __insertResult__(self, indexCode, quantileDatas):

        delSql = """
            DELETE FROM fin_index_quantile
            WHERE index_code =%s
        """
        self.localDb.ExecNoneQuery(delSql, (indexCode,))

        sql = """
            INSERT INTO fin_index_quantile
            (industry_code, index_code, min, tf, fi, sf, max)
            VALUES
            (%(industry_code)s, %(index_code)s, %(min)s, %(tf)s, %(fi)s, %(sf)s, %(max)s);
        """
        self.localDb.ExecMany(sql, quantileDatas)

    def run(self):
        # 加载设置
        settings = self.__loadSettings__()
        self.indexMapping = {s["code"]: s["name"] for s in settings}

        for setting in tqdm(settings, desc="settings", position=0, file=sys.stdout):

            indexCode = setting["code"]

            # 加载指标数据
            finList = self.__loadFinIndexList__(2022, indexCode)
            if len(finList) == 0:
                continue

            quantileDatas = []

            # 按证监会一级行业分组
            finList.sort(key=lambda x: (x["industry"]))
            for industryCode, datas in groupby(finList, key=itemgetter('industry')):
                # self.logger.info(f"计算:{self.industryMapping[industryCode]} {industryCode}, 指标：{self.indexMapping[indexCode]} {indexCode}")
                values = list({CommonUtils.strToNum(dd["index_value"]) for dd in list(datas)})
                values = list(filter(None, values))

                quantileData = {
                    "industry_code": industryCode,
                    "index_code": indexCode,
                }

                if len(values) == 0:
                    quantileData["min"] = None
                    quantileData["tf"] = None
                    quantileData["fi"] = None
                    quantileData["sf"] = None
                    quantileData["max"] = None
                else:
                    quantileData["min"] = f"{round(np.min(values),6)}"
                    quantileData["tf"] = f"{round(np.quantile(values, .25), 6)}"
                    quantileData["fi"] = f"{round(np.quantile(values, .50), 6)}"
                    quantileData["sf"] = f"{round(np.quantile(values, .75), 6)}"
                    quantileData["max"] = f"{round(np.max(values),6)}"

                quantileDatas.append(quantileData)

            # 一个指标更新（全行业）
            self.__insertResult__(indexCode, quantileDatas)


def __main__():
    cleanScreen()

    logger = Logger()

    t = time.perf_counter()
    logger.info("指标计算 0.0.1")

    localDb = ProdDb(logSql=False, autocommit=True)

    sync = CalcIndicatorQuantile(logger=logger, localDb=localDb)
    sync.run()

    cast = (time.perf_counter() - t)
    m = math.floor(cast / 60)
    s = cast - m * 60
    logger.info('指标计算结束 %s 总耗时: %d分%.3f秒' % (datetime.datetime.now(), m, s))


# 程序入口
if __name__ == "__main__":
    __main__()
